﻿#region
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Y2M2.Properties;
using YoutubeExtractor;

#endregion

namespace Y2M2
{
    public partial class ClipControl : UserControl
    {
        public ClipControl()
        {
            InitializeComponent();

            _worker.WorkerReportsProgress = true;
            _worker.DoWork += Worker_DoWork;
            _worker.ProgressChanged += Worker_ProgressChanged;
        }

        public ClipControl(string url)
            : this()
        {
            Url = url;
        }

        public string Url { get; private set; }

        public bool Finished { get; private set; }

        private readonly BackgroundWorker _worker = new BackgroundWorker();

        private void ClipControl_OnLoaded(object sender, RoutedEventArgs e)
        {
            if (Url == null)
                return;

            txtTitle.Text = "다운로드 준비중...";

            _worker.RunWorkerAsync(Url);
        }

        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            switch ((ReportPhase)e.ProgressPercentage)
            {
                case ReportPhase.Title:
                    txtTitle.Text = (string)e.UserState;
                    break;
                case ReportPhase.Thumbnail:
                    imgThumbnail.Source = GetBitmapImage((MemoryStream)e.UserState);
                    break;
                case ReportPhase.Finish:
                    txtTitle.SetValue(TextBlock.FontWeightProperty, FontWeights.Bold);
                    prbProgress.Visibility = Visibility.Hidden;
                    Finished = true;
                    break;
            }
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            string url = (string)e.Argument;

            var clip = YoutubeHelper.GetClipInfoFromUrl(url);
            _worker.ReportProgress((int)ReportPhase.Title, clip.Title);

            var memoryStream = GetMemoryStream(clip.ThumbnailUrl);
            _worker.ReportProgress((int)ReportPhase.Thumbnail, memoryStream);

            string videoPath = DownloadVideo(clip);

            if (Settings.Default.AudioOnly)
                ConvertToAudio(clip, videoPath);

            _worker.ReportProgress((int)ReportPhase.Finish);
        }

        private void ConvertToAudio(Clip clip, string videoPath)
        {
            string audioPath = Path.Combine(Settings.Default.DownloadRoot, clip.Title + ".mp3");

            string argument = string.Format(@"-i ""{0}"" -vn -f mp3 ""{1}""", videoPath, audioPath);

            Process process = new Process();
            process.StartInfo = new ProcessStartInfo("ffmpeg.exe", argument);
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.CreateNoWindow = true;
            process.Start();
            process.WaitForExit();

            File.Delete(videoPath);
        }

        private string DownloadVideo(Clip clip)
        {
            string videoPath = Path.Combine(Settings.Default.DownloadRoot, clip.Title + clip.VideoExtension);

            var videoDownloader = new VideoDownloader(clip.VideoInfo, videoPath);
            videoDownloader.DownloadProgressChanged += VideoDownloader_DownloadProgressChanged;
            videoDownloader.Execute();

            return videoPath;
        }

        private void VideoDownloader_DownloadProgressChanged(object sender, ProgressEventArgs e)
        {
            Dispatcher.Invoke(new Action(() => prbProgress.Value = (int)e.ProgressPercentage));
        }

        private MemoryStream GetMemoryStream(string url)
        {
            const int BytesToRead = 100;

            WebRequest request = WebRequest.Create(new Uri(url, UriKind.Absolute));
            request.Timeout = -1;
            WebResponse response = request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            BinaryReader reader = new BinaryReader(responseStream);
            MemoryStream memoryStream = new MemoryStream();

            byte[] bytebuffer = new byte[BytesToRead];
            int bytesRead = reader.Read(bytebuffer, 0, BytesToRead);

            while (bytesRead > 0)
            {
                memoryStream.Write(bytebuffer, 0, bytesRead);
                bytesRead = reader.Read(bytebuffer, 0, BytesToRead);
            }

            return memoryStream;
        }

        private BitmapImage GetBitmapImage(MemoryStream memoryStream)
        {
            var image = new BitmapImage();
            image.BeginInit();
            memoryStream.Seek(0, SeekOrigin.Begin);

            image.StreamSource = memoryStream;
            image.EndInit();

            return image;
        }

        private enum ReportPhase
        {
            Title,
            Thumbnail,
            Download,
            Convert,
            Finish
        }
    }
}